package flex.cc.uac.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import flex.cc.PublicUtil;
import flex.cc.base.constant.GlobalConstant;
import flex.cc.base.dto.LoginAuthDto;
import flex.cc.base.enums.ErrorCodeEnum;
import flex.cc.uac.dao.UacRoleDao;
import flex.cc.uac.dto.role.RoleBindActionDto;
import flex.cc.uac.dto.role.RoleBindMenuDto;
import flex.cc.uac.dto.role.RoleBindUserDto;
import flex.cc.uac.entity.UacActionEntity;
import flex.cc.uac.entity.UacMenuEntity;
import flex.cc.uac.entity.UacRoleActionEntity;
import flex.cc.uac.entity.UacRoleEntity;
import flex.cc.uac.entity.UacRoleMenuEntity;
import flex.cc.uac.entity.UacRoleUserEntity;
import flex.cc.uac.entity.UacUserEntity;
import flex.cc.uac.exceptions.UacBizException;
import flex.cc.uac.service.UacActionService;
import flex.cc.uac.service.UacMenuService;
import flex.cc.uac.service.UacRoleActionService;
import flex.cc.uac.service.UacRoleMenuService;
import flex.cc.uac.service.UacRoleService;
import flex.cc.uac.service.UacRoleUserService;
import flex.cc.uac.service.UacUserService;
import flex.cc.uac.vo.BindAuthVo;
import flex.cc.uac.vo.MenuVo;
import lombok.extern.slf4j.Slf4j;

@Service("uacRoleService")
@Slf4j
public class UacRoleServiceImpl extends ServiceImpl<UacRoleDao, UacRoleEntity> implements UacRoleService {

    @Resource
    private UacRoleUserService uacRoleUserService;

    @Resource
    private UacRoleActionService uacRoleActionService;

    @Resource
    private UacRoleMenuService uacRoleMenuService;

    @Resource
    private UacMenuService uacMenuService;
    @Resource
    private UacActionService uacActionService;
    @Resource
    private UacUserService uacUserService;

    @Resource
    private UacRoleDao uacRoleDao;

    @Override
    public IPage<UacRoleEntity> queryRoleListWithPage(UacRoleEntity role) {
        Wrapper queryWrapper = new QueryWrapper<UacRoleEntity>()
                .eq(PublicUtil.isNotEmpty(role.getStatus()),"status",role.getStatus())
                .like(PublicUtil.isNotEmpty(role.getRoleCode()),"role_code",role.getRoleCode())
                .like(PublicUtil.isNotEmpty(role.getRoleName()),"role_name",role.getRoleName())
                .orderByDesc("update_time");
        IPage<UacRoleEntity> page = this.page(new Page<>(role.getPageNum(),role.getPageSize()), queryWrapper);
        return page;
    }

    @Override
    public boolean deleteRoleById(Long roleId) {
        //查询该角色下是否有用户绑定, 有的话提醒不能删除
        if (null == roleId) {
            throw new IllegalArgumentException(ErrorCodeEnum.UAC10012001.msg());
        }

        // 超级管理员不能删除
        if (Objects.equals(roleId, GlobalConstant.Sys.SUPER_MANAGER_ROLE_ID)) {
            throw new UacBizException(ErrorCodeEnum.UAC10012003);
        }

        List<UacRoleUserEntity> uruList = uacRoleUserService.listByRoleId(roleId);

        if (!uruList.isEmpty()) {
            uacRoleUserService.deleteByRoleId(roleId);
        }

        uacRoleActionService.deleteByRoleId(roleId);
        uacRoleMenuService.deleteByRoleId(roleId);

        return this.removeById(roleId);
    }

    @Override
    public void batchDeleteByIdList(List<Long> roleIdList) {
        log.info("批量删除角色. idList={}", roleIdList);
        Preconditions.checkArgument(PublicUtil.isNotEmpty(roleIdList), "删除角色ID不存在");

        List<UacRoleUserEntity> uruList = uacRoleUserService.listByRoleIdList(roleIdList);
        if (!uruList.isEmpty()) {
            uacRoleUserService.deleteByRoleIdList(roleIdList);
        }

        uacRoleMenuService.deleteByRoleIdList(roleIdList);
        uacRoleActionService.deleteByRoleIdList(roleIdList);

        boolean result = this.removeByIds(roleIdList);
        if (!result) {
            throw new UacBizException(ErrorCodeEnum.UAC10012006, Joiner.on(GlobalConstant.Symbol.COMMA).join(roleIdList));
        }
    }

    @Override
    public void saveRole(UacRoleEntity role, LoginAuthDto loginAuthDto) {
        role.setUpdateInfo(loginAuthDto);
        this.saveOrUpdate(role);
    }

    /**
     * 绑定/解绑角色-用户
     * @param roleBindUserDto
     * @param loginAuthDto
     */
    @Override
    public void bindUserRole(RoleBindUserDto roleBindUserDto, LoginAuthDto loginAuthDto) {
        if (roleBindUserDto == null) {
            log.error("参数不能为空");
            throw new IllegalArgumentException("参数不能为空");
        }
        Long roleId = roleBindUserDto.getRoleId();
        Long loginUserId = loginAuthDto.getUserId();
        List<Long> userIdList = roleBindUserDto.getUserIdList();

        if (null == roleId) {
            throw new IllegalArgumentException(ErrorCodeEnum.UAC10012001.msg());
        }
        UacRoleEntity role = this.getById(roleId);
        if (role == null) {
            log.error("找不到角色信息 roleId={}", roleId);
            throw new UacBizException(ErrorCodeEnum.UAC10012005, roleId);
        }

        if (PublicUtil.isNotEmpty(userIdList) && userIdList.contains(loginUserId)) {
            log.error("不能操作当前登录用户 userId={}", loginUserId);
            throw new UacBizException(ErrorCodeEnum.UAC10011023);
        }
        // 绑定所选用户
        for (Long userId : userIdList) {
            UacUserEntity uacUser = uacUserService.queryByUserId(userId);
            if (PublicUtil.isEmpty(uacUser)) {
                log.error("找不到绑定的用户 userId={}", userId);
                throw new UacBizException(ErrorCodeEnum.UAC10011024, userId);
            }
            if("N".equals(roleBindUserDto.getStatus())) {
                Map<String,Object> map = new HashMap<>();
                map.put("role_id",roleId);
                map.put("user_id",userId);
                uacRoleUserService.removeByMap(map);
            } else {
            	uacRoleUserService.saveRoleUser(userId, roleId);
            }
        }
    }

    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public BindAuthVo getActionTreeByRoleId(Long roleId,String isEdit) {
        BindAuthVo bindAuthVo = new BindAuthVo();
        if (roleId == null) {
            throw new UacBizException(ErrorCodeEnum.UAC10012001);
        }

        UacRoleEntity roleById = this.getById(roleId);
        if (roleById == null) {
            log.error("找不到角色信息 roleId={}", roleId);
            throw new UacBizException(ErrorCodeEnum.UAC10012005, roleId);
        }

        List<UacMenuEntity> uacMenus = uacMenuService.listMenuListByRoleId(roleId);
        if (PublicUtil.isEmpty(uacMenus)) {
            throw new UacBizException(ErrorCodeEnum.UAC10013009);
        }

        List<UacActionEntity> uacActions = new ArrayList<>();
        List<Long> checkedAuthList = new ArrayList<>();
        if("1".equals(isEdit)){
            // 查询所有的权限信息
            uacActions = uacActionService.listActionList(uacMenus);
            // 获取所有绑定的菜单和按钮权限Id集合
            checkedAuthList = uacActionService.getCheckedActionList(roleId);
        }else{
            // 查询该角色所拥有的权限信息
            uacActions = uacActionService.listActionListByRoleId(roleId);
        }
        // 合并菜单和按钮权限 递归生成树结构
        uacMenus = uacMenuService.getMenuTreeByMenuId(uacMenus);
        List<MenuVo> menuVoList = this.getAuthList(uacMenus, uacActions);
        List<Tree<Long>> tree = buildTree(menuVoList);
        bindAuthVo.setAuthTree(tree);
        bindAuthVo.setCheckedAuthList(checkedAuthList);
        return bindAuthVo;
    }



    @Override
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public BindAuthVo getMenuTreeByRoleId(Long roleId,String isEdit) {
        BindAuthVo bindAuthVo = new BindAuthVo();
        Preconditions.checkArgument(roleId != null, ErrorCodeEnum.UAC10012001.msg());

        UacRoleEntity roleById = this.getById(roleId);
        if (roleById == null) {
            log.error("找不到角色信息 roleId={}", roleId);
            throw new UacBizException(ErrorCodeEnum.UAC10012005, roleId);
        }
        List<UacMenuEntity> uacMenus = new ArrayList<>();
        List<Long> checkedAuthList = new ArrayList<>();
        if("1".equals(isEdit)){
            // 查询所有的菜单信息
            uacMenus = uacMenuService.list();
            // 获取所有绑定的菜单Id集合
            checkedAuthList = uacMenuService.getCheckedMenuList(roleId);
        }else{
            // 查询该角色所拥有的菜单信息
            uacMenus = uacMenuService.listMenuListByRoleId(roleId);
        }

        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setParentIdKey("pid");
        treeNodeConfig.setWeightKey("seq");
        treeNodeConfig.setNameKey("label");
        treeNodeConfig.setChildrenKey("children");
        treeNodeConfig.setDeep(5);
        List<Tree<Long>> treeList = TreeUtil.build(uacMenus, 0L, treeNodeConfig, (treeNode, tree) -> {
            tree.setId(treeNode.getId());
            tree.setParentId(treeNode.getPid());
            tree.setWeight(treeNode.getNumber());
            tree.setName(treeNode.getMenuName());
        });

        bindAuthVo.setAuthTree(treeList);
        bindAuthVo.setCheckedAuthList(checkedAuthList);
        return bindAuthVo;
    }

    private List<MenuVo> getAuthList(List<UacMenuEntity> uacMenus, List<UacActionEntity> uacActions) {
        List<MenuVo> menuVoList = Lists.newArrayList();
        MenuVo menuVo;
        for (UacMenuEntity uacMenu : uacMenus) {
            menuVo = new MenuVo();
            BeanUtils.copyProperties(uacMenu, menuVo);
            menuVo.setRemark("menu");
            menuVoList.add(menuVo);
        }
        if (PublicUtil.isNotEmpty(uacActions)) {
            for (UacActionEntity uacAction : uacActions) {
                menuVo = new MenuVo();
                menuVo.setId(uacAction.getId());
                menuVo.setMenuName(uacAction.getActionName());
                menuVo.setMenuCode(uacAction.getActionCode());
                menuVo.setPid(uacAction.getMenuId());
                menuVo.setUrl(uacAction.getUrl());
                menuVo.setRemark("action");
                menuVoList.add(menuVo);
            }
        }
        return menuVoList;
    }

    private List<Tree<Long>> buildTree(List<MenuVo> menuVoList){
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setParentIdKey("pid");
        treeNodeConfig.setWeightKey("seq");
        treeNodeConfig.setNameKey("label");
        treeNodeConfig.setChildrenKey("children");
        treeNodeConfig.setDeep(5);
        List<Tree<Long>> treeList = TreeUtil.build(menuVoList, 0L, treeNodeConfig, (treeNode, tree) -> {
            tree.setId(treeNode.getId());
            tree.setParentId(treeNode.getPid());
            tree.setWeight(treeNode.getNumber());
            tree.setName(treeNode.getMenuName());
            tree.putExtra("menuCode",treeNode.getMenuCode());
            tree.putExtra("url",treeNode.getUrl());
            tree.putExtra("remark",treeNode.getRemark());
        });
        return treeList;
    }

    @Override
    public void bindMenu(RoleBindMenuDto roleBindMenuDto) {

        Long roleId = roleBindMenuDto.getRoleId();
        Set<Long> menuIdList = roleBindMenuDto.getMenuIdList();

        if (roleId == null) {
            throw new UacBizException(ErrorCodeEnum.UAC10012001);
        }

        if (Objects.equals(roleId, GlobalConstant.Sys.SUPER_MANAGER_ROLE_ID)) {
            log.error("越权操作, 超级管理员用户不允许操作");
            throw new UacBizException(ErrorCodeEnum.UAC10011023);
        }

        UacRoleEntity uacRole = uacRoleDao.selectById(roleId);
        if (uacRole == null) {
            log.error("找不到角色信息. roleId={}", roleId);
            throw new UacBizException(ErrorCodeEnum.UAC10012005, roleId);
        }

        // TODO 校验参数的合法性(这里不写了 累得慌 也就是校验菜单和权限是否存在)
        List<UacRoleMenuEntity> uacRoleMenuList = uacRoleMenuService.listByRoleId(roleId);

        if (PublicUtil.isNotEmpty(uacRoleMenuList)) {
            uacRoleMenuService.deleteByRoleId(roleId);
        }

        // menuSet actionIdList 如果为空则 取消该角色所有权限
        if (PublicUtil.isEmpty(menuIdList)) {
            log.error("传入菜单权限Id为空, 取消菜单权限");
        } else {
            // 绑定菜单
            uacRoleMenuService.insert(roleId, menuIdList);
        }
    }

    @Override
    public void bindAction(RoleBindActionDto grantAuthRole) {
        Long roleId = grantAuthRole.getRoleId();
        Set<Long> actionIdList = grantAuthRole.getActionIdList();

        if (roleId == null) {
            throw new UacBizException(ErrorCodeEnum.UAC10012001);
        }

        if (Objects.equals(roleId, GlobalConstant.Sys.SUPER_MANAGER_ROLE_ID)) {
            log.error("越权操作, 超级管理员用户不允许操作");
            throw new UacBizException(ErrorCodeEnum.UAC10011023);
        }

        UacRoleEntity uacRole = uacRoleDao.selectById(roleId);
        if (uacRole == null) {
            log.error("找不到角色信息. roleId={}", roleId);
            throw new UacBizException(ErrorCodeEnum.UAC10012005, roleId);
        }

        // TODO 校验参数的合法性(这里不写了 累得慌 也就是校验菜单和权限是否存在)
        List<UacRoleActionEntity> uacRoleActionList = uacRoleActionService.listByRoleId(roleId);

        if (PublicUtil.isNotEmpty(uacRoleActionList)) {
            uacRoleActionService.deleteByRoleId(roleId);
        }

        if (PublicUtil.isEmpty(actionIdList)) {
            log.error("传入按钮权限Id为空, 取消所有按钮权限");
        } else {
        	Set<Long> actionIds = new HashSet<Long>();
        	for(Long menuId : actionIdList) {
        		UacMenuEntity menu = uacMenuService.getById(menuId);
        		if(menu == null || (menu != null && menu.getLevel().intValue() >= 2)) {
        			actionIds.add(menuId);
        		}
        	}
            // 绑定权限
            uacRoleActionService.insert(roleId, actionIds);
        }
    }




}
